using System;
using System.Collections.Generic;
using System.Data;
using System.Text;

using Forecast.Database;

namespace Forecast.Business
{
    public class Activity
    {
        #region Variables

        private Load _load;
        private Save _save;

        #endregion
        #region Contructors

        // Forces use of overload
        private Activity() { }

        public Activity(string databaseConnectionString)
        {
            // TODO
            _load = new Load(databaseConnectionString);
            _save = new Save(databaseConnectionString);
        }

        #endregion
        #region Interface

        public int[] GetAllTrades(Prediction prediction)
        {
            IList<Offer> allOffers = _load.GetAllOffers();
            return ActivePredictions.GetAllTrades(prediction, allOffers);
        }

        public IList<NewsItem> GetLatest()
        {
            IList<NewsItem> allNewsItems = _load.GetAllNewsItems();
            SelectedNews selectedNews = new SelectedNews();
            return selectedNews.GetLatest(allNewsItems);            
        }

        public IList<NewsItem> GetTopMainNews()
        {
            IList<NewsItem> allNewsItems = _load.GetAllNewsItems();
            SelectedNews selectedNews = new SelectedNews();
            return selectedNews.GetTopMainNews(allNewsItems);
        }

        public IList<NewsItem> GetAllMainNews()
        {
            IList<NewsItem> allNewsItems = _load.GetAllNewsItems();
            SelectedNews selectedNews = new SelectedNews();
            return selectedNews.GetAllMainNews(allNewsItems);
        }

        public IList<NewsItem> GetTopPredictionNews(int predictionId)
        {
            IList<NewsItem> allNewsItems = _load.GetAllNewsItems();
            Prediction prediction = _load.GetPrediction(predictionId);
            SelectedNews selectedNews = new SelectedNews();
            return selectedNews.GetTopPredictionNews(allNewsItems, prediction);
        }

        public IList<NewsItem> GetAllPredictionNews(int predictionId)
        {
            IList<NewsItem> allNewsItems = _load.GetAllNewsItems();
            Prediction prediction = _load.GetPrediction(predictionId);
            SelectedNews selectedNews = new SelectedNews();
            return selectedNews.GetAllPredictionNews(allNewsItems, prediction);
        }

        public IList<NewsItem> GetTopPlayerNews(int playerId)
        {
            IList<NewsItem> allNewsItems = _load.GetAllNewsItems();
            Player player = _load.GetPlayer(playerId);
            SelectedNews selectedNews = new SelectedNews();
            return selectedNews.GetTopPlayerNews(allNewsItems, player);
        }

        public IList<NewsItem> GetAllPlayerNews(int playerId)
        {
            IList<NewsItem> allNewsItems = _load.GetAllNewsItems();
            Player player = _load.GetPlayer(playerId);
            SelectedNews selectedNews = new SelectedNews();
            return selectedNews.GetAllPlayerNews(allNewsItems, player);
        }

        public DataTable GetPredictionResults(int predictionId)
        {
            Prediction prediction = _load.GetPrediction(predictionId);
            IList<Player> allPlayers = _load.GetAllPlayers();
            IList<PredictionResult> predictionResults = _load.GetPredictionResults(prediction);
            return new PredictionResults().GetPredictionResults(prediction, allPlayers, predictionResults);
        }

        public int GetNumStocksForSaleForPlayer(int playerId, int predictionId)
        {
            Player player = _load.GetPlayer(playerId);
            Prediction prediction = _load.GetPrediction(predictionId);
            IList<Offer> activeOffersInPrediction = _load.GetActiveOffers(prediction);
            TraderOverview traderOverview = new TraderOverview(playerId, _load);
            return traderOverview.GetNumStocksForSale(prediction, activeOffersInPrediction);
        }

        public TraderOverview GetTraderOverview(int playerId)
        {
            return new TraderOverview(playerId, _load);
        }

        public DataTable GetPortfolio(int playerId)
        {
            Player player = _load.GetPlayer(playerId);
            IList<Prediction> predictions = _load.GetAllActivePredictions();
            IList<Offer> offers = _load.GetOffers(player, true);
            IList<Holding> holdings = _load.GetHoldings(player);
            return new Portfolio(player, this).GetPortfolio(predictions, offers, holdings);
        }

        public DataTable GetActivePredictions()
        {
            IList<Prediction> activePredictions = _load.GetAllActivePredictions();
            IList<Offer> allOffers = _load.GetAllOffers();
            return new ActivePredictions().GetActivePredictions(activePredictions, allOffers);
        }

        public DataTable GetTradersOverview()
        {
            IList<Prediction> activePredictions = _load.GetAllActivePredictions();
            IList<Prediction> closedPredictions = _load.GetAllClosedPredictions();
            IList<Player> players = _load.GetAllPlayers();
            IList<Offer> offers = _load.GetAllActiveOffers();
            IList<Holding> holdings = _load.GetAllHoldings();
            IList<Medal> medals = _load.GetAllMedals();
            IList<PredictionResult> allPredictionResults = _load.GetAllPredictionResults();
            IList<Offer> allOffers = _load.GetAllOffers();
            IList<NewsItem> allNewsItems = _load.GetAllNewsItems();
            TradersOverview tradersOverview = new TradersOverview();
            return tradersOverview.GetOverview(activePredictions, closedPredictions, players, offers, holdings, medals, allPredictionResults, allOffers, allNewsItems);
        }

        public DataTable GetMedalsForPlayer(int playerId)
        {
            Player player = _load.GetPlayer(playerId);
            IList<Medal> allMedals = _load.GetAllMedals();
            IList<PredictionResult> allPredictionResults = _load.GetAllPredictionResults();
            IList<Prediction> allClosedPredictions = _load.GetAllClosedPredictions();
            Medals medals = new Medals();
            return medals.GetMedalsForPlayer(player, allMedals, allPredictionResults, allClosedPredictions);
        }

        public void NewOffer(NewOfferParams newOfferParams)
        {
            if (!newOfferParams.IsBuy)
                NewSellOffer(newOfferParams);
            else
                NewBuyOffer(newOfferParams);            
        }

        public void AcceptOffer(AcceptOfferParams acceptOfferParams)
        {
            Offer offer = _load.GetOffer(acceptOfferParams.OfferId);
            if (!offer.IsBuy)
                AcceptSellOffer(acceptOfferParams, offer);
            else
                AcceptBuyOffer(acceptOfferParams, offer);
            
        }

        public void RemoveOffer(int offerId)
        {
            Offer offer = _load.GetOffer(offerId);
            Player player = _load.GetPlayer(offer.PlayerId);
            Prediction prediction = _load.GetPrediction(offer.PredictionId);
            Holding holding = _load.GetHolding(player, prediction);

            RemoveOffer removeOffer = new RemoveOffer();
            removeOffer.Execute(offer, player, holding, prediction);

            _save.EditOffer(removeOffer.RemoveOfferOffer);
            _save.EditPlayer(removeOffer.RemoveOfferPlayer);
            _save.NewNewsItem(removeOffer.RemoveOfferNewsItem);
            if (removeOffer.RemoveOfferHolding.Id > -1)
                _save.EditHolding(removeOffer.RemoveOfferHolding);
            else
                _save.NewHolding(removeOffer.RemoveOfferHolding);
        }

        public void ActivatePrediction(int predictionId)
        {
            Prediction prediction = _load.GetPrediction(predictionId);
            IList<Player> allPlayers = _load.GetAllPlayers();

            ActivatePrediction activatePrediction = new ActivatePrediction();
            activatePrediction.Execute(prediction, allPlayers);

            _save.EditPrediction(activatePrediction.ActivatePredictionPrediction);
            foreach (Player player in activatePrediction.ActivatePredictionPlayers)
                _save.EditPlayer(player);
            foreach (Holding holding in activatePrediction.ActivatePredictionHoldings)
                _save.NewHolding(holding);
            _save.NewNewsItem(activatePrediction.ActivatePredictionNewsItem);
        }

        public void PredictionEnd(int predictionId, bool succeeded)
        {
            Prediction prediction = _load.GetPrediction(predictionId);
            IList<Player> allPlayers = _load.GetAllPlayers();
            IList<Holding> allHoldings = _load.GetHoldings(prediction);
            IList<Offer> allOffers = _load.GetOffers(prediction);
            IList<Medal> allMedals = _load.GetAllMedals();

            EndPrediction endPrediction = new EndPrediction();
            endPrediction.Execute(prediction, allPlayers, allHoldings, allOffers, allMedals, succeeded);

            _save.EditPrediction(endPrediction.EndPredictionPrediction);
            foreach (Player player in endPrediction.EndPredictionPlayers)
                _save.EditPlayer(player);
            foreach (Holding holding in endPrediction.EndPredictionHoldings)
            {
                if (holding.Id > -1)
                    _save.DeleteHolding(holding.Id);
            }
            foreach (PredictionResult predictionResult in endPrediction.EndPredictionPredictionResults)
                _save.NewPredictionResult(predictionResult);
            foreach (NewsItem newsItem in endPrediction.EndPredictionNewsItems)
                _save.NewNewsItem(newsItem);
            _save.EditOffers(allOffers);
        }

        public void UpdateAllPlayers()
        {
            IList<Player> allPlayers = _load.GetAllPlayers();
            IList<Offer> allOffers = _load.GetAllOffers();
            IList<Holding> allHoldings = _load.GetAllHoldings();

            UpdatePlayer updatePlayer = new UpdatePlayer();
            updatePlayer.Execute(allPlayers, allHoldings, allOffers);

            _save.EditPlayers(updatePlayer.UpdatePlayerPlayers);
            _save.EditOffers(updatePlayer.UpdatePlayerOffers);
            _save.EditHoldings(updatePlayer.UpdatePlayerHoldings);
        }

        #endregion
        #region Private methods

        private void AcceptSellOffer(AcceptOfferParams acceptOfferParams, Offer offer)
        {
            Player acceptor = _load.GetPlayer(acceptOfferParams.PlayerId);
            Prediction prediction = _load.GetPrediction(offer.PredictionId);
            Player offerer = _load.GetPlayer(offer.PlayerId);
            IList<Offer> allActiveOffersInPrediction = _load.GetActiveOffers(prediction);
            int numHiddenStocks = new HiddenHolding(acceptor, prediction, allActiveOffersInPrediction).NumHiddenStocks;
            Holding buyerHolding = _load.GetHolding(acceptor, prediction);
            if (buyerHolding.Id == 0)
            {
                buyerHolding.NumPredictions = 0;
                buyerHolding.PlayerId = acceptor.Id;
                buyerHolding.PredictionId = prediction.Id;
            }

            AcceptOffer acceptOffer = new AcceptOffer();
            acceptOffer.Sell(acceptor, offerer, buyerHolding, prediction, offer, acceptOfferParams.NumPredictions, numHiddenStocks);

            _save.NewNewsItem(acceptOffer.AcceptOfferNewsItemBuyer);
            _save.NewNewsItem(acceptOffer.AcceptOfferNewsItemSeller);
            _save.EditPlayer(acceptOffer.AcceptOfferBuyer);
            _save.EditPlayer(acceptOffer.AcceptOfferSeller);
            _save.EditOffer(acceptOffer.AcceptOfferOffer);
            if (acceptOffer.AcceptOfferSubOffer != null)
                _save.NewOffer(acceptOffer.AcceptOfferSubOffer);
            _save.EditPrediction(acceptOffer.AcceptOfferPrediction);

            if (acceptOffer.AcceptOfferBuyerHolding.Id <= 0)
                _save.NewHolding(acceptOffer.AcceptOfferBuyerHolding);
            else
                _save.EditHolding(acceptOffer.AcceptOfferBuyerHolding);

        }

        private void AcceptBuyOffer(AcceptOfferParams acceptOfferParams, Offer offer)
        {
            Player acceptor = _load.GetPlayer(acceptOfferParams.PlayerId);
            Player offerer = _load.GetPlayer(offer.PlayerId);
            Prediction prediction = _load.GetPrediction(offer.PredictionId);
            Holding buyerHolding = _load.GetHolding(offerer, prediction);
            Holding sellerHolding = _load.GetHolding(acceptor, prediction);
            IList<Offer> allActiveOffersInPrediction = _load.GetActiveOffers(prediction);
            int numHiddenStocks = new HiddenHolding(offerer, prediction, allActiveOffersInPrediction).NumHiddenStocks;

            AcceptOffer acceptOffer = new AcceptOffer();
            acceptOffer.Buy(offerer, acceptor, buyerHolding, sellerHolding, prediction, offer, acceptOfferParams.NumPredictions, numHiddenStocks);

            _save.NewNewsItem(acceptOffer.AcceptOfferNewsItemBuyer);
            _save.NewNewsItem(acceptOffer.AcceptOfferNewsItemSeller);
            _save.EditPlayer(acceptOffer.AcceptOfferBuyer);
            _save.EditPlayer(acceptOffer.AcceptOfferSeller);
            _save.EditOffer(acceptOffer.AcceptOfferOffer);
            if (acceptOffer.AcceptOfferSubOffer != null)
                _save.NewOffer(acceptOffer.AcceptOfferSubOffer);
            _save.EditPrediction(acceptOffer.AcceptOfferPrediction);
            _save.EditHolding(acceptOffer.AcceptOfferBuyerHolding);

            if (acceptOffer.AcceptOfferSellerHolding.NumPredictions == 0)
                _save.DeleteHolding(acceptOffer.AcceptOfferSellerHolding.Id);
            else
                _save.EditHolding(acceptOffer.AcceptOfferSellerHolding);
        }

        private void NewBuyOffer(NewOfferParams newOfferParams)
        {
            Player player = _load.GetPlayer(newOfferParams.PlayerId);
            Prediction prediction = _load.GetPrediction(newOfferParams.PredictionId);

            NewOffer newOffer = new NewOffer();
            newOffer.Buy(player, prediction, newOfferParams.NumPredictions, newOfferParams.Price, newOfferParams.EndDate);

            _save.EditPlayer(newOffer.NewOfferPlayer);
            _save.NewOffer(newOffer.NewOfferOffer);
            _save.NewNewsItem(newOffer.NewOfferNewsItem);
        }

        private void NewSellOffer(NewOfferParams newOfferParams)
        {
            Player player = _load.GetPlayer(newOfferParams.PlayerId);
            Prediction prediction = _load.GetPrediction(newOfferParams.PredictionId);
            Holding holding = _load.GetHolding(player, prediction);

            NewOffer newOffer = new NewOffer();
            newOffer.Sell(player, holding, prediction, newOfferParams.NumPredictions, newOfferParams.Price, newOfferParams.EndDate);

            _save.EditHolding(newOffer.NewOfferHolding);
            _save.NewOffer(newOffer.NewOfferOffer);
            _save.NewNewsItem(newOffer.NewOfferNewsItem);
        }

        internal int GetResultForPlayer(int playerId, int predictionId)
        {
            Player player = _load.GetPlayer(playerId);
            Prediction prediction = _load.GetPrediction(predictionId);
            Holding holding = _load.GetHolding(player, prediction);
            IList<Offer> offers = _load.GetOffers(player, true);
            Results results = new Results();
            return results.GetResultForPlayer(player, prediction, holding, offers);
        }

        #endregion
    }
}
